#include "preHeader.h"
#include "GameServerSession.h"
#include "GameServerSessionHandler.h"
#include "GameServerMgr.h"
#include "SocialServer.h"
#include "GateServerListener.h"
#include "S2GuildPacketHandler.h"
#include "Guild/GuildMgr.h"
#include "S2RankPacketHandler.h"
#include "Rank/RankMgr.h"
#include "S2OperatingPacketHandler.h"
#include "Operating/OperatingActivityMgr.h"
#include "Game/TransMgr.h"

GameServerSession::GameServerSession()
: RPCSession("GameServerSession", CGX_RPC_INVOKE_RESP)
, m_isReady(false)
{
}

GameServerSession::~GameServerSession()
{
}

int GameServerSession::HandlePacket(INetPacket *pck)
{
	if (IsReady() || pck->GetOpcode() < FLAG_GAME2SOCIAL_MSG_NEED_REGISTER_BEGIN) {
		return sGameServerSessionHandler.HandlePacket(this, *pck);
	} else {
		return SessionHandleUnhandle;
	}
}

void GameServerSession::OnShutdownSession()
{
	if (IsReady()) {
		sTransMgr.RemoveAllClient();
		sGameServerMgr.RemoveGameServer(this);
	}
	WLOG("Close GameServerSession.");
	RPCSession::OnShutdownSession();
}

void GameServerSession::OnRecvPacket(INetPacket *pck)
{
	const uint32 opcode = pck->GetOpcode();
	switch (opcode) {
	case CGX_BROADCAST_SERVICES:
		BroadcastPacket2AllServices(pck->UnpackPacket());
		delete pck;
		return;
	}

	if (sS2GuildPacketHandler.CanHandle(opcode)) {
		sGuildMgr.PushRecvPacket(IServerService::NewServerPacket(pck));
		return;
	}
	if (sS2RankPacketHandler.CanHandle(opcode)) {
		sRankMgr.PushRecvPacket(IServerService::NewServerPacket(pck));
		return;
	}
	if (sS2OperatingPacketHandler.CanHandle(opcode)) {
		sOperatingActivityMgr.PushRecvPacket(IServerService::NewServerPacket(pck));
		return;
	}

	RPCSession::OnRecvPacket(pck);
}

void GameServerSession::BroadcastPacket2AllServices(const INetPacket &pck)
{
	const uint32 opcode = pck.GetOpcode();
	if (sS2GuildPacketHandler.CanHandle(opcode)) {
		sGuildMgr.PushRecvPacket(IServerService::NewServerPacket(pck.Clone()));
	}
	if (sS2RankPacketHandler.CanHandle(opcode)) {
		sRankMgr.PushRecvPacket(IServerService::NewServerPacket(pck.Clone()));
	}
	if (sS2OperatingPacketHandler.CanHandle(opcode)) {
		sOperatingActivityMgr.PushRecvPacket(IServerService::NewServerPacket(pck.Clone()));
	}
}

int GameServerSessionHandler::HandleRegister(GameServerSession *pSession, INetPacket &pck)
{
	if (sGameServerMgr.GetGameServerSession() != NULL) {
		WLOG("GameServerSession[%p] is already registered.",
			sGameServerMgr.GetGameServerSession());
		return SessionHandleKill;
	}

	NetPacket notify(CGX_UPDATE_GAME_SERVER);
	pSession->BroadcastPacket2AllServices(notify);

	uint32 serverId;
	int64 startServerTime, lastOperatingEventTime;
	pck >> serverId >> startServerTime >> lastOperatingEventTime;
	sOperatingActivityMgr.InitLastEventTime(lastOperatingEventTime);
	sGameServerMgr.SetStartServerTime(startServerTime);
	sGameServerMgr.SetServerId(serverId);

	sGameServerMgr.RegisterGameServer(pSession);
	pSession->m_isReady = true;

	NetPacket resp(SGX_REGISTER_RESP);
	resp << sGateServerListener.addr() << sGateServerListener.port();
	pSession->PushSendPacket(resp);

	NLOG("GameServer Register Success.");
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushServerId(GameServerSession *pSession, INetPacket &pck)
{
	uint32 serverId;
	pck >> serverId;
	sGameServerMgr.SetServerId(serverId);
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleRestoreCharacters(GameServerSession *pSession, INetPacket &pck)
{
	while (!pck.IsReadableEmpty()) {
		uint32 uid, gsGateSN, gateClientSN;
		pck >> uid >> gsGateSN >> gateClientSN;
		sTransMgr.AddClient(new TransMgr::Client{uid, gsGateSN, gateClientSN});
	}
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleCharacterOnline(GameServerSession *pSession, INetPacket &pck)
{
	uint32 uid, gsGateSN, gateClientSN;
	pck >> uid >> gsGateSN >> gateClientSN;
	sTransMgr.AddClient(new TransMgr::Client{uid, gsGateSN, gateClientSN});
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleCharacterOffline(GameServerSession *pSession, INetPacket &pck)
{
	uint32 uid;
	pck >> uid;
	sTransMgr.RemoveClient(uid);
	return SessionHandleSuccess;
}
